package ldh.im.fxbase.util;

import javafx.concurrent.Task;
import ldh.rpc.exception.RpcException;
import org.slf4j.Logger;

import java.util.concurrent.*;
import java.util.function.Consumer;
import java.util.function.Function;

public class ThreadPoolUtil {

//    private static final ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
    private static final ThreadPoolExecutor executorService = new ThreadPoolExecutor(6, 20, 2L, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(1000));
    private static final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);

    // 特殊线程池
    private static final ExecutorService specialExecutorService = Executors.newCachedThreadPool();

    private static final Logger LOGGER = LoggerUtil.getFileLogger(ThreadPoolUtil.class);

    public static void close() {
        executorService.shutdownNow();
        scheduledExecutorService.shutdownNow();
        specialExecutorService.shutdownNow();
    }

    public static <V> Future<V> submit(Callable<V> callable) {
        loggerThreadPool();
        return executorService.submit(()->{
            try {
               return (V)callable.call();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });
    }

    public static <V> Task<V> submit(Function<Task, V> function) {
        loggerThreadPool();
        Task<V> task = new Task() {

            @Override
            protected V call() throws Exception {
                updateMessage("");
                return function.apply(this);
            }
        };
        executorService.submit(task);
        return task;
    }

    public static <V> Task<V> submitTask(Task<V> task) {
        loggerThreadPool();
        if(task.getOnFailed() == null) {
            task.setOnFailed(e->{
                LOGGER.error("处理数据失败", task.getException());
                DialogUtil.alert("错误", "处理数据失败");
            });
        }
        executorService.submit(task);
        return task;
    }

    public static <V> Task<V> submitTask(Task<V> task, String businessMsg) {
        loggerThreadPool();
        executorService.submit(task);
        String errorMsg = businessMsg == null ? "处理数据失败" : businessMsg + "失败";
        task.setOnFailed(e->{
            LOGGER.error(errorMsg, task.getException());
            if(task.getException() instanceof RpcException) {
                RpcException rpcException = (RpcException) task.getException();
                String errMsg = rpcException.getMessage();
                DialogUtil.alert("错误", errMsg);
            } else {
                DialogUtil.alert("错误", errorMsg);
            }
        });
        return task;
    }

    public static <V> Future<V> submit(Runnable runnable) {
        loggerThreadPool();
        return (Future<V>) executorService.submit(()->{
            try {
                runnable.run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    public static <V> Future<V> submitSpecial(Runnable runnable) {
        loggerThreadPool();
        return (Future<V>) specialExecutorService.submit(()->{
            try {
                runnable.run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    public static <V> Future<V> submit(Runnable runnable, Consumer<Exception> consumer) {
        loggerThreadPool();
        return (Future<V>) executorService.submit(()->{
            Exception errorMessage = null;
            try {
                runnable.run();
            } catch (Exception e) {
                errorMessage = e;
            }
            if (errorMessage != null && consumer != null) {
                consumer.accept(errorMessage);
            }
        });
    }

    public static <V> ScheduledFuture<V> schedule(Runnable runnable, int milisecond) {
        Task<Void> task = new Task<Void>() {
            protected Void call() {
                try {
                    runnable.run();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        };

        return (ScheduledFuture<V>) scheduledExecutorService.schedule(task, milisecond, TimeUnit.MILLISECONDS);
    }

    public static <V> ScheduledFuture<V> schedule(Callable<V> callable) {
        return (ScheduledFuture<V>) scheduledExecutorService.schedule(()->{
            try {
                callable.call();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 100, TimeUnit.MILLISECONDS);
    }

    public static ScheduledFuture scheduleAtFixedRate(Runnable runnable, long initialDelay, long period, TimeUnit unit) {
        return scheduledExecutorService.scheduleAtFixedRate(()->{
            try {
                runnable.run();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, initialDelay, period, unit);
    }

    private static void loggerThreadPool() {
        LOGGER.info("线程池中线程数目：" + executorService.getPoolSize()
                + "，队列中等待执行的任务数目：" + executorService.getQueue().size()
                + "，已执行完的任务数目：" + executorService.getCompletedTaskCount()
                + "，活动线程数目：" + executorService.getActiveCount()
        );
    }
}
